<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <title>Vue发布-订阅模式</title>
</head>

<body>
    <div id="app">
        <p>
            vue.js采用数据劫持结合发布-订阅者模式，通过Object.defineProperty()来劫持data中各个属性的setter、getter,在数据变动时，发布消息给订阅者，触发响应的监听回调。
            （setter和getter是对象的存储器属性，是一个函数，用来获取和设置值）
        </p>
        订阅试图-1：<span class="box-1">第一个值</span>
        订阅试图-2：<span class="box-2">第二个值</span>
    </div>
    <script>
        //订阅器模型
        var Dep = {
            list: {},
            listen: function (key, fn) {
                (this.list[key] || (this.list[key] = [])).push(fn);
            },
            trigger: function () {
                var key = Array.prototype.shift.call(arguments);
                fns = this.list[key];
                if (!fns || fns.length == 0) return;
                for (var i = 0, fn; fn = fns[i++];) {
                    console.log('trigger for arguments', arguments)
                    fn.apply(this, arguments);//发布消息附带的参数
                }
            }
        };

        //劫持的方法 Object.defineProperty方法，给对象的属性赋值
        var dataHijack = function ({ data, tag, datakey, selector }) {
            var value = '';
            el = document.querySelector(selector);
            Object.defineProperty(data, datakey, {
                //拿到数据
                get: function () {
                    console.log('我获取到值了');
                    return value;
                },
                //设置数据
                set: function (newVal) {
                    console.log('我设置值了');
                    value = newVal;
                    Dep.trigger(tag, newVal); //发布消息，更新变化
                }
            })
            //绑定观察者
            Dep.listen(tag, function (text) {
                el.innerHTML = text;
            })
        };

        var dataObj = {}; //数据
        //数据劫持
        dataHijack({
            data: dataObj,
            tag: 'view-1',
            datakey: 'one',
            selector: '.box-1'
        });
        // dataHijack({
        //     data: dataObj,
        //     tag: 'view-2',
        //     datakey: 'two',
        //     selector: '.box-2'
        // });

        let a = 11;
        function test1() {
            console.log('1111',this)
            this.a = 22;
            let b = () => {
                console.log('222',this)
            }
            b()
        }
        let x = new test1();
        test1()
    </script>
</body>

</html>